package com.aaron.test;


import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.function.Function.identity;

/**
 * 名称、姓名、邮箱、手机号、地址脱敏
 */
public class InfoMosaicUtil {

    private static final String[] SPECIAL_ADDR = {"名人公馆"};

    private static final String[] RESERVERD_ADDR = {"奉贤区"};



    /**
     * @author yangxin
     */
    public enum InfoType {
        // 姓名
        NAME(InfoMosaicUtil::changeName),
        // 地址
        ADDRESS(InfoMosaicUtil::changeAddress),
        // 电话
        PHONE(InfoMosaicUtil::changePhoneNumber),
        // 邮箱
        EMAIL(InfoMosaicUtil::changeemail);

        InfoType(Function<String, String> function) {
            this.function = function;
        }

        private final Function<String, String> function;

        public Function<String, String> getFunction() {
            return function;
        }

    }

    /**
     * @author yangxin
     */
    public static class Mosaic<T> {
        /**
         * get 方法
         */
        public Function<T, String> get;
        /**
         * set 方法
         */
        public BiConsumer<T, String> set;
        /**
         * 实现脱敏的枚举
         */
        public InfoType infoType;


        public Mosaic(Function<T, String> get, BiConsumer<T, String> set, InfoType infoType) {
            this.get = get;
            this.set = set;
            this.infoType = infoType;
        }

        private List<Mosaic<T>> list;

        public Mosaic() {

        }

        public Mosaic<T> builder() {
            if (CollectionUtils.isEmpty(list)) {
                list = new ArrayList<>();
            }
            return this;
        }

        public Mosaic<T> add(Function<T, String> get, BiConsumer<T, String> set, InfoType infoType) {
            list.add(new Mosaic<>(get, set, infoType));
            return this;
        }

        public List<Mosaic<T>> list() {
            Objects.requireNonNull(list);
            return list;
        }

    }


    /**
     * 名字脱敏
     *
     * @param name
     * @return
     */
    public static String changeName(String name) {
        if (StringUtils.isNotBlank(name) && name.length() > 1) {
            String newName = name.replaceAll("[^\u4E00-\u9FA5]", "");
            if (newName.length() < 2) {
                return name;
            }
            StringBuilder sb = new StringBuilder(newName);
            if (newName.length() < 4) {
                name = sb.replace(1, 2, "*").toString();
            } else {
                name = sb.replace(2, newName.length(), "**").toString();
            }
        }
        return name;
    }

    /**
     * 手机号脱敏
     *
     * @param phone
     * @return
     */
    public static String changePhoneNumber(String phone) {
        if (StringUtils.isNotBlank(phone) && phone.length() > 7) {
            StringBuilder sb = new StringBuilder(phone);
            phone = sb.replace(3, 7, "****").toString();
        }
        return phone;
    }

    /**
     * 邮箱用****号隐藏前面的字母
     *
     * @return
     */
    public static String changeemail(String email) {
        String emails = email.replaceAll("(\\w?)(\\w+)(\\w)(@\\w+\\.[a-z]+(\\.[a-z]+)?)", "$1****$3$4");
        return emails;
    }


    /**
     * {@link #changeAddress(String, String)}
     */
    public static String changeAddress(String address) {
        return changeAddress(address, "奉贤区");
    }

    /**
     * 地址脱敏
     *
     * @param reserved 不需要脱敏的 “单个或多个字符”
     * @author yangxin
     */
    public static String changeAddress(String address, String reserved) {
        if (StringUtils.isBlank(address)) {
            return "";
        }
        address = address.replaceAll("(\\w)", "*");//数字脱敏
        int firstIndex = 0;
        if (!StringUtils.isBlank(reserved)) {
            int i = address.indexOf(reserved);
            if (i != -1) {
                firstIndex = i + reserved.length();
                //防止数组越界异常
                if (firstIndex >= address.length()) {
                    return address;
                }
            }
        }

        if (ArrayUtils.isNotEmpty(RESERVERD_ADDR)) {
            for (String reserve : RESERVERD_ADDR) {
                int i = address.indexOf(reserve);
                if (i != -1) {

                }
            }
        }

        //对地址标识无法确定的地址进行脱敏
        for (String special : SPECIAL_ADDR) {
            if (address.contains(special)) {
                address.replace(special,Arrays.stream("special".split("")).map(t -> "*").collect(Collectors.joining()));
            }
        }

        Supplier<Stream<String>> supplier = () -> Stream.of("州", "县", "市", "乡", "镇", "村", "居", "街", "路", "号", "弄", "层", "室", "楼","区");
        final int lastIndex = supplier.get()
                .map(address::lastIndexOf)
                .max(Comparator.comparing(identity()))
//				.map(m -> m == -1 ? address.length() : m)
                .orElseThrow(RuntimeException::new);
        if (lastIndex == -1) {
            //未匹配到地址关键字，直接返回
            return address;
        }

        String b = Arrays.stream(address.substring(firstIndex, lastIndex).split(""))
                .map(
                        m -> supplier.get()
                                .filter(f -> f.equals(m))
                                .findFirst().orElse("*")
                )
                .reduce((t1, t2) -> t1 + t2)
                .orElseThrow(RuntimeException::new);
        return address.substring(0, firstIndex) + b + address.substring(lastIndex);
    }


    /**
     * 集合脱敏
     * <p>
     * service层脱敏参考以下代码
     * <pre>
     *        List<DASDept> list = dasDeptMapper.getListByLast(last);
     *
     *         mosaic(list, new InfoMosaicUtil.Mosaic<DASDept>().builder()
     *                 .add(DASDept::getDeptFullName, DASDept::setDeptFullName, InfoMosaicUtil.InfoType.ADDRESS)
     *                 .add(DASDept::getDeptName, DASDept::setDeptName, InfoMosaicUtil.InfoType.ADDRESS)
     *                 .add(DASDept::getDeptLinkman, DASDept::setDeptLinkman, InfoMosaicUtil.InfoType.NAME)
     *                 .add(DASDept::getDeptLinkmanEmail, DASDept::setDeptLinkmanEmail, InfoMosaicUtil.InfoType.EMAIL)
     *                 .add(DASDept::getDeptLinkmanPhone, DASDept::setDeptLinkmanPhone, InfoMosaicUtil.InfoType.PHONE)
     *                 .list());
     *         System.out.println(list);
     * </pre>
     *
     * @author yangxin
     */
    public static <T> void mosaic(Collection<T> collection, List<Mosaic<T>> list) {
        collection.forEach(c -> list.forEach(v -> v.set.accept(c, v.infoType.function.apply(Optional.ofNullable(v.get.apply(c)).orElse("")))));
    }


    public static void main(String[] args) {
        String s = changeAddress("0智能井盖02(上海省奉贤区12智3州1智23县1智23市1智23乡1智23镇智智智智智智智智智智智智智智智智智智智)", "奉贤区");
        System.out.println(s);
    }
}
